#include     <stdio.h>  
#include     <stdlib.h>  
#include     <unistd.h>   
#include     <sys/types.h>  
#include     <sys/stat.h>   
#include     <fcntl.h>  
#include     <termios.h>  
#include     <errno.h> 
#include     <pthread.h>


/*-------------UART control----------------------*/

#define UART_FALSE  -1
#define UART_TRUE   0

int fd_uart = -1;
static pthread_mutex_t uart_mut     = PTHREAD_MUTEX_INITIALIZER;

int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300};
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300};
void set_speed(int fd, int speed){
  int   i; 
  int   status; 
  struct termios   Opt;
  status=tcgetattr(fd, &Opt);  
  printf("status=%d\n",status);
  if  (status != 0) {       
    perror("tcgetattr fd");  
    return;     
  }    

  for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) { 

    if  (speed == name_arr[i]) {     
      printf("i=%d,speed_arr[i]=%d\n",i,speed_arr[i]);
      tcflush(fd, TCIOFLUSH);     
      cfsetispeed(&Opt, speed_arr[i]);  
      cfsetospeed(&Opt, speed_arr[i]);   
      //Opt.c_cflag |= speed_arr[i];
      //Opt.c_iflag = IGNPAR;
      //Opt.c_oflag = 0;
      tcflush(fd,TCIOFLUSH);   
      status = tcsetattr(fd, TCSANOW, &Opt);  
      if  (status != 0) {       
        perror("tcsetattr fd");  
        return;     
      }
    }  
  }
}
int set_Parityinit(int fd,int databits,int stopbits,int parity)
{ 
  struct termios options; 

  if  ( tcgetattr( fd,&options)  !=  0) { 
    perror("SetupSerial 1");     
    return(UART_FALSE);  
  }
  options.c_cflag |=(CLOCAL|CREAD);
  options.c_cflag &= ~CSIZE; 
  options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
  options.c_oflag  &= ~OPOST;   /*Output*/
  // options.c_cc[VMIN]=0;
  //  options.c_cc[VTIME]=10;

  switch (databits) /*ÉèÖÃÊýŸÝÎ»Êý*/
  {   
  case 7: 
    options.c_cflag |= CS7; 
    break;
  case 8:     
    options.c_cflag |= CS8;
    break;   
  default:    
    fprintf(stderr,"Unsupported data size/n"); return (UART_FALSE);  
  }
  switch (parity) 
  {   
  case 'n':
  case 'N':    
    options.c_iflag &= ~INPCK;     /* Enable parity checking */ 
    break;  
  case 'o':   
  case 'O':     
    options.c_cflag |= (PARODD | PARENB); 
    options.c_iflag |= INPCK;             /* Disnable parity checking */ 
    break;  
  case 'e':  
  case 'E':   
    options.c_cflag |= PARENB;     /* Enable parity */    
    options.c_cflag &= ~PARODD;  
    options.c_iflag |= INPCK;       /* Disnable parity checking */
    break;
  case 'S': 
  case 's':  /*as no parity*/   
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    break;  
  default:   
    fprintf(stderr,"Unsupported parity/n");    
    return (UART_FALSE);  
  }  

  switch (stopbits)
  {   
  case 1:    
    options.c_cflag &= ~CSTOPB;  
    break;  
  case 2:    
    options.c_cflag |= CSTOPB;  
    break;
  default:    
    fprintf(stderr,"Unsupported stop bits/n");  
    return (UART_FALSE); 
  } 

  /* Set input parity option */ 

  if (parity != 'n')   
    options.c_iflag |= INPCK; 

  tcflush(fd,TCIFLUSH);
  options.c_cc[VTIME] = 5; 
  options.c_cc[VMIN] = 0; /* define the minimum bytes data to be readed*/

  if (tcsetattr(fd,TCSANOW,&options) != 0)   
  { 
    perror("SetupSerial 3");   
    return (UART_FALSE);  
  } 
  return (UART_TRUE);  
}
int set_Parity(int fd,int databits,int stopbits,int parity)
{
  struct termios options;
  if ( tcgetattr( fd,&options) != 0)
  {
    perror("SetupSerial 1");
    return(UART_FALSE);
  }
  options.c_cflag &= ~CSIZE;
  switch (databits) 
  {
  case 7:
    options.c_cflag |= CS7;
    break;
  case 8:
    options.c_cflag |= CS8;
    break;
  default:
    fprintf(stderr,"Unsupported data size\n");
    return (UART_FALSE);
  }
  switch (parity)
  {
  case 'n':
  case 'N':
    //        options.c_cflag &= ~PARENB;   /* Clear parity enable */
    //        options.c_iflag &= ~INPCK;     /* Enable parity checking */
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
    options.c_oflag &= ~OPOST;   /*Output*/
    break;
  case 'o':
  case 'O':
    options.c_cflag |= (PARODD | PARENB); 
    options.c_iflag |= INPCK;             /* Disnable parity checking */
    break;
  case 'e':
  case 'E':
    options.c_cflag |= PARENB;     /* Enable parity */
    options.c_cflag &= ~PARODD;   
    options.c_iflag |= INPCK;       /* Disnable parity checking */
    break;
  case 'S':
  case 's': /*as no parity*/
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    break;
  default:
    fprintf(stderr,"Unsupported parity\n");
    return (UART_FALSE);
  }

  switch (stopbits)
  {
  case 1:
    options.c_cflag &= ~CSTOPB;
    break;
  case 2:
    options.c_cflag |= CSTOPB;
    break;
  default:
    fprintf(stderr,"Unsupported stop bits\n");
    return (UART_FALSE);
  }
  /* Set input parity option */
  if ((parity != 'n')&&(parity != 'N'))
    options.c_iflag |= INPCK;

  options.c_cc[VTIME] = 5; // 0.5 seconds
  options.c_cc[VMIN] = 1;

  options.c_cflag &= ~HUPCL;
  options.c_iflag &= ~INPCK;
  options.c_iflag |= IGNBRK;
  options.c_iflag &= ~ICRNL;
  options.c_iflag &= ~IXON;
  options.c_lflag &= ~IEXTEN;
  options.c_lflag &= ~ECHOK;
  options.c_lflag &= ~ECHOCTL;
  options.c_lflag &= ~ECHOKE;
  options.c_oflag &= ~(ONLCR|OCRNL);
  options.c_cflag |= CLOCAL | CREAD; 
  options.c_iflag &= ~ (IXON | IXOFF | IXANY);
  options.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);
  options.c_iflag &= ~ (INLCR | IGNCR);

  tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
  if (tcsetattr(fd,TCSANOW,&options) != 0)
  {
    perror("SetupSerial 3");
    return (UART_FALSE);
  }

  return (UART_TRUE);
}


/*********************************************************************/

int openUART(char *Dev)
{
  fd_uart = open( Dev, O_RDWR| O_NOCTTY | O_NDELAY  ); 
  //| O_NOCTTY | O_NDELAY     O_RDWR|O_NONBLOCK     
  if (-1 == fd_uart)         
  {                         
    perror("Can't Open Serial Port");
    return -1;             
  }       
  else   
  {
    //fcntl(fd, F_SETFL, 0);
    fcntl(fd_uart, F_SETFL, FNDELAY);

    set_speed(fd_uart,115200);
    if (set_Parity(fd_uart,8,1,'N') == UART_FALSE)  {
      printf("Set Parity Error\n");
      return -1;
    }
    return fd_uart;
  }
}
int UART_init()
{
  char *dev  = "/dev/ttyS1"; //serial port 1
  int fd;
  fd = openUART(dev);
  if(fd <0)
  {
    mLog("open UART dev %s error\n",dev);
  }
  mLog("open UART dev %s successfully\n",dev);
  return fd;

}
int writeUART(unsigned char* buffer,int num)
{
  int result=0;
  if(fd_uart < 0)
  {
    mLog("UART is not open, cannot write!\n");
    return 0;
  }
//  pthread_mutex_lock(&uart_mut); 
  result = write(fd_uart,buffer,num);
//  pthread_mutex_unlock(&uart_mut); 
  return result;
}
int readUART(unsigned char* buffer,int num)
{
  int result=0;
  if(fd_uart < 0)
  {
    mLog("UART is not open, cannot read!\n");
    return 0;
  }
//  pthread_mutex_lock(&uart_mut); 
  result = read(fd_uart,buffer,num);
//  pthread_mutex_unlock(&uart_mut); 
  return result;
}
void closeUART()
{
  close(fd_uart);
}

int WriteSerialPort(int serialfd,const char *data,int datalength)
{
  int len, total_len;
  for(total_len = 0;total_len<datalength;){
    len=0;
    len=write(serialfd,&data

      [total_len],datalength - total_len);

    if(len >0)
    {total_len += len;}
    else{
      tcflush(serialfd,TCOFLUSH);
      break;
    }
  }
  return(total_len);
}
int serial_read(int fd, char *str,unsigned int len,unsigned int timeout)
{
  fd_set rfds;
  struct timeval tv;
  int ret;							
  int sret;							
  char * ptr;

  ptr = str;		

  FD_ZERO(&rfds);				
  FD_SET(fd,&rfds);			
  tv.tv_sec  = timeout / 1000;
  tv.tv_usec = (timeout%1000)*1000;


  //if(sizeof(&str) < len)
  //	len = sizeof(str);



  sret = select(fd+1,&rfds,NULL,NULL,&tv);	

  if(sret == -1)						
  {
    perror("select:");
  }
  else if(sret > 0)				
  {
    printf("read...\n");
    ret = read(fd,ptr,len);

  }
  return ret;
}
